package api

import (
	"TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/admin/services"
	"TaskAssignmentSystem/internal/pkg/middleware/handler"
	"TaskAssignmentSystem/pkg/db/redis"
	"TaskAssignmentSystem/pkg/oss"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"errors"
	"fmt"
	"github.com/go-the-way/exl"
	"github.com/kataras/iris/v12"
	"io/ioutil"
	"os"
	"strconv"
	"time"
)

type AdvCreateRequest struct {
	AdvText   string `json:"adv_text"`  //广告说明
	AdvPath   string `json:"adv_path"`  //广告图片路径
	Hyperlink string `json:"hyperlink"` //超链接
	Sort      uint   `json:"sort"`      //排序编号
}

func AdvCreateHandler(ctx iris.Context) {
	var RequestParams AdvCreateRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var serve services.SystemAdvService
	if err := serve.AdvCreate(RequestParams.AdvText, RequestParams.AdvPath, RequestParams.Hyperlink, RequestParams.Sort, claims.Id); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type AdvQueryRequest struct {
	AdvId uint `json:"adv_id" validate:"required"`
}

func AdvInfoHandler(ctx iris.Context) {
	var RequestParams AdvQueryRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var serve services.SystemAdvService
	if res, err := serve.AdvFindById(RequestParams.AdvId); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(res))
		return
	}
}

type AdvListRequest struct {
	Page     int64 `json:"page"`
	PageSize int64 `json:"page_size"`
}

func AdvListHandler(ctx iris.Context) {
	var RequestParams AdvListRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var serve services.SystemAdvService
	if total, list, err := serve.AdvFindAll(RequestParams.Page, RequestParams.PageSize); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(iris.Map{"count": total, "list": list}))
		return
	}
}

type AdvUpdateRequest struct {
	UpType      string `json:"up_type" validate:"required"`
	AdvId       uint   `json:"adv_id" validate:"required"`
	OfflineTime string `json:"offline_time"` //下架时间，格式：2023-03-01 14:48:05
	Sort        uint   `json:"sort"`         //排序编号
}

func AdvUpdateHandler(ctx iris.Context) {
	var RequestParams AdvUpdateRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var err error
	var serve services.SystemAdvService
	if _, err := serve.AdvFindById(RequestParams.AdvId); err != nil {
		ctx.JSON(utils.ResponseServerError(errors.New("该广告不存在")))
		return
	}
	if RequestParams.UpType == "1" {
		//修改下架时间
		offlineTime, err := time.Parse("2006-01-02 15:04:05", RequestParams.OfflineTime)
		if err != nil {
			ctx.JSON(utils.ResponseServerError(errors.New("下架时间格式不正确")))
			return
		}
		err = serve.AdvUpdateOffline(RequestParams.AdvId, offlineTime)
	} else if RequestParams.UpType == "2" {
		//修改排序号
		err = serve.AdvUpdateSort(RequestParams.AdvId, RequestParams.Sort)
	} else if RequestParams.UpType == "3" {
		//下架
		err = serve.AdvOffline(RequestParams.AdvId)
	} else if RequestParams.UpType == "4" {
		//上架
		err = serve.AdvOnline(RequestParams.AdvId)
	} else if RequestParams.UpType == "5" {
		//删除
		err = serve.AdvDel(RequestParams.AdvId)
	} else {
		err = errors.New("修改类型错误")
	}
	if err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseOK())
		return
	}
}

func AdvUpdatePathHandler(ctx iris.Context) {
	advIdStr := ctx.PostValue("adv_id")
	advIdInt, err := strconv.Atoi(advIdStr)
	if err != nil {
		ctx.JSON(utils.ResponseServerError(errors.New("参数异常")))
		return
	}
	advId := uint(advIdInt)
	var serve services.SystemAdvService
	if _, err := serve.AdvFindById(advId); err != nil {
		ctx.JSON(utils.ResponseServerError(errors.New("该广告不存在")))
		return
	}

	_, handle, err := utils.FormFile(ctx, "file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, err := handle.Open()
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}

	//获取当前时间的月份
	currentMonth := time.Now().In(utils.LocationZone).Format("2006-01")

	//关闭打开文件
	defer file.Close()
	fileByte, err := ioutil.ReadAll(file) //获取上传文件字节流
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}

	var ossClient oss.BucketClient
	if handle.Filename == "image.jpg" {
		handle.Filename = fmt.Sprintf("%d.jpeg", time.Now().Unix())
	}

	fileName := fmt.Sprintf("task-assign/adv/%s/%s", currentMonth, handle.Filename)
	if err := ossClient.UpBytes(fileByte, fileName); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	} else {
		webPath := fmt.Sprintf("%s/%s", utils.ServerConf.AliOssConf.CallBackHost, fileName)
		if err := serve.AdvUpdatePath(advId, webPath); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		} else {
			ctx.JSON(utils.ResponseData(webPath))
			return
		}
	}
}

type ReadExcelAdv struct {
	Sort        uint   `excel:"轮播序号（必填）"`
	AdvPath     string `excel:"图片链接（必填）"`
	OnlineTime  string `excel:"上架时间（必填）"`
	OfflineTime string `excel:"下架时间（必填）"`
	Hyperlink   string `excel:"超链接（必填）"`
}

func (*ReadExcelAdv) Configure(rc *exl.ReadConfig) {}

func ExcelAdvImportsHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*ReadExcelAdv](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var advServe dao.Common[dao.SystemAdv]
		advObjs := make([]dao.SystemAdv, len(models)-1)
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			advObjs[index].Sort = model.Sort
			advObjs[index].AdvPath = model.AdvPath
			OnlineTime, err := time.ParseInLocation(timehandler.FormatLayoutTime, model.OnlineTime, time.Local)
			if err != nil {
				ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: "第[" + utils.IntToString(i+1) + "]行[" + model.OnlineTime + "]格式错误"})
				return
			}
			advObjs[index].OnlineTime = OnlineTime
			OfflineTime, err := time.ParseInLocation(timehandler.FormatLayoutTime, model.OfflineTime, time.Local)
			if err != nil {
				ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: "第[" + utils.IntToString(i+1) + "]行[" + model.OfflineTime + "]格式错误"})
				return
			}
			advObjs[index].OfflineTime = OfflineTime
			advObjs[index].Hyperlink = model.Hyperlink
			if err := advServe.CreateOneReturnId(&advObjs[index]).Error; err != nil {
				ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
				return
			}
			//创建redis 过期事件(广告开启和关闭)
			expirationOpen := advObjs[index].OnlineTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			openKey := fmt.Sprintf("adv_open@%d", advObjs[index].Id)
			if setNX := redis.RedisGClient.SetNX(openKey, "", time.Duration(expirationOpen)*time.Second).Err(); setNX != nil {
				//return setNX
			}
			//广告关闭
			expirationClose := advObjs[index].OfflineTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			closeKey := fmt.Sprintf("adv_close@%d", advObjs[index].Id)
			if setNX := redis.RedisGClient.SetNX(closeKey, "", time.Duration(expirationClose)*time.Second).Err(); setNX != nil {
				//return setNX
			}
			index++
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type ExportAdvRecords struct {
	Sort            uint      `excel:"轮播序号"`
	AdvPath         string    `excel:"图片链接"`
	OnlineTime      time.Time `excel:"上架时间"`
	OfflineTime     time.Time `excel:"下架时间"`
	TotalClicks     int64     `excel:"总点击量"`
	NotRepeatClicks int64     `excel:"非重复点击量"`
	Hyperlink       string    `excel:"超链接"`
}

func (m *ExportAdvRecords) Configure(wc *exl.WriteConfig) {}

type ExportAdvRecordsRequest struct {
	Ids []uint `json:"ids" validate:"required"`
}

func ExportAdvRecordsHandler(ctx iris.Context) {
	var RequestParams ExportAdvRecordsRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var serve services.SystemAdvService
	queryMap := map[string]interface{}{}
	if len(RequestParams.Ids) > 0 {
		queryMap["id"] = RequestParams.Ids
	}
	ExportData, err := serve.AdvFindByIds(queryMap, "sort")
	//_, ExportData, err := serve.AdvFindAll(-1, 10000)
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	index := 0
	exportAdvRecords := make([]*ExportAdvRecords, len(ExportData))
	for _, model := range ExportData {
		exportAdvRecords[index] = &ExportAdvRecords{}
		exportAdvRecords[index].Sort = model.Sort
		exportAdvRecords[index].AdvPath = model.AdvPath
		exportAdvRecords[index].OnlineTime = model.OnlineTime
		exportAdvRecords[index].OfflineTime = model.OfflineTime
		exportAdvRecords[index].Hyperlink = model.Hyperlink
		exportAdvRecords[index].TotalClicks = model.TotalClicks
		exportAdvRecords[index].NotRepeatClicks = model.NotRepeatClicks
		index++
	}
	unix := time.Now().UnixNano()
	if err := exl.Write(fmt.Sprintf("./export/export_adv_records_%d.xlsx", unix), exportAdvRecords); err != nil {
		fmt.Println("write excel err:" + err.Error())
		return
	}
	tempFilename := fmt.Sprintf("./export/export_adv_records_%d.xlsx", unix)
	//删除本地临时文件
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/export_adv_records_%d.xlsx", unix))
	bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/advexport/export_adv_records_%d.xlsx", unix))
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/advexport/export_adv_records_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
	return
}
